package com.woniu.filter;

import com.alibaba.fastjson.JSON;
import com.woniu.util.JWTUtil;
import com.woniu.util.ResData;
import com.woniu.util.ResEnum;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 校验是否登录的过滤器
 * 1：实现 Filter 接口，重写 doFilter方法
 * 2：在容器中注册自己的过滤器
 *          第一种：@Component + @WebFilter(urlPatterns = "/*")
 *                  不推荐：如果有多个过滤器，不好指定顺序
 *          第二种：用 FilterRegistrationBean 注册过滤器
 *
 *  实现步骤
 *  1：获取请求头中的jwt
 *      不能获取，返回一个状态码，结束方法 return
 *      能获取，走到第二步
 *
 *  2：校验前端携带过来的 jwt 是否合法
 *      不合法 返回一个状态码，结束方法 return
 *      合法 走到第三步
 *
 *  3:给 JWT续期
 *
 *  4：放行
 */
@Component
//@WebFilter(urlPatterns = "/*")
public class LoginFilter implements Filter {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @SneakyThrows   //lombok 提供的注解式抛异常
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//        System.out.println("进入拦截器");
        HttpServletRequest request = (HttpServletRequest) servletRequest;

        //返回类型的字符集
        servletResponse.setContentType("application/json;charset=utf-8");
        //判断此次请求是否需要携带 JWT
        // getRequestURL() http://localhost:8081/user/login
        // getRequestURI() /user/login
        String requestURI = request.getRequestURI();
        if(!matchURI(requestURI)){
            /**
             *  1：获取请求头中的jwt
             *      不能获取，返回一个状态码，结束方法 return
             *      能获取，走到第二步
             */
            String tokenHeader = request.getHeader("token");
            if(tokenHeader==null){
                //没有携带jwt
                servletResponse.getWriter().print(JSON.toJSONString(new ResData<>().fail(ResEnum.NO_LOGIN)));
                return;
            }
            /**
             *  2：校验前端携带过来的 jwt 是否合法
             *      不合法 返回一个状态码，结束方法 return
             *      合法 走到第三步
             */
            if(!JWTUtil.decode(tokenHeader)){
                servletResponse.getWriter().print(JSON.toJSONString(new ResData<>().fail(ResEnum.NO_LOGIN)));
                return;
            }
            //获取redis 中 jwt 对比
            Map userMap = JWTUtil.getJWTUserInfo(tokenHeader);
            Long userId = (Long) userMap.get("userId");
            String redisJWT = redisTemplate.opsForValue().get("jwt-"+userId);

            if(!tokenHeader.equals(redisJWT)){
                servletResponse.getWriter().print(JSON.toJSONString(new ResData<>().fail(ResEnum.NO_LOGIN)));
                return;
            }

            //JWT续期
            redisTemplate.opsForValue().set("jwt-"+userId,tokenHeader,30, TimeUnit.MINUTES);
        }

        //放行，如果系统只有一个过滤器，那么放行就会放行到controller层
        // 如果系统是过滤器链，那么就会放行到下一个过滤器

        //放行代码如下：
        filterChain.doFilter(servletRequest,servletResponse);
    }

    /**
     * 匹配请求是否在免登录请求中
     * @param uri
     * @return
     */
    public Boolean matchURI(String uri){
        String[] freeURI = {"/user/login","/book/queryAll"};
        for (String s : freeURI) {
            if (s.equals(uri)){
                return true;
            }
        }
        return false;
    }
}
